﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml.FormulaParsing.Exceptions;

namespace NewDevice.TCPIP
{
    /// <summary>
    /// 12路直流电压采集模块控制类 提供基于TCP/IP协议的12路直流电压采集功能
    /// </summary>
    public class Zh3412134M2_V2
    {
        #region 初始化设置指令

        //01 06 00 EF 00 09 //采样率设置为500Hz
        //01 06 00 E6 00 00 //关闭can自动上传
        //01 06 00 E4 00 01 //启用网口自动上传

        #endregion 初始化设置指令

        /// <summary>
        /// 服务器IP地址
        /// </summary>
        private string _serverIp;

        /// <summary>
        /// 服务器端口号
        /// </summary>
        private int _serverPort;

        /// <summary>
        /// TCP客户端对象
        /// </summary>
        private TcpClient _client = null!;

        /// <summary>
        /// 网络数据流
        /// </summary>
        private NetworkStream _stream = null!;

        /// <summary>
        /// 寄存器历史值缓存（通道号 -&gt; 历史值列表）
        /// </summary>
        private readonly Dictionary<int, List<short>?> _registerValues = new Dictionary<int, List<short>?>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serverIp">服务器IP地址，默认为127.0.0.1</param>
        /// <param name="serverPort">服务器端口号，默认为5000</param>
        public Zh3412134M2_V2(string serverIp = "127.0.0.1", int serverPort = 5000)
        {
            _serverIp = serverIp;
            _serverPort = serverPort;
            _noteData = new();
            _stopNote = new ManualResetEvent(false);
        }

        public int MeasureRange { get; set; } = 30;

        /// <summary>
        /// 获取所有通道的电压历史值（已转换为实际电压值）
        /// </summary>
        /// <remarks>电压值计算公式：读值*30(量程)/10000，并保留3位小数</remarks>
        public Dictionary<int, List<double>> RegisterValues
        {
            get
            {
                return _registerValues.ToDictionary(
                    kvp => kvp.Key,
                    kvp => kvp.Value!.Select(v => Math.Round(v * MeasureRange / 10000.0, 3)).ToList()
                );
            }
        }

        /// <summary>
        /// 启动TCP客户端连接
        /// </summary>
        /// <returns>异步任务</returns>
        /// <exception cref="System.Net.Sockets.SocketException">网络连接失败时抛出</exception>
        public void Open()
        {
            _client = new TcpClient();
            _client.Connect(_serverIp, _serverPort);

            _stream = _client.GetStream();

            Task.Run(() =>
            {
                while (_isReading)
                {
                    ReadBuffer();
                }
            });
        }

        private bool _isReading = true;
        private bool _isNote = false;
        private List<byte> _noteData;
        private ManualResetEvent _stopNote;

        public void StartNote()
        {
            if (_isNote)
            {
                _isNote = false;
                _stopNote = new ManualResetEvent(false);
                if (!_stopNote.WaitOne(100))
                {
                    throw new Exception($"{nameof(Zh3412134M2_V2)} {nameof(StartNote)} wait stop timeout");
                }
            }
            _registerValues.Clear();
            _noteData = new List<byte>();
            _isNote = true;
        }

        public void StopNote()
        {
            _isNote = false;
            ParseData();
        }

        private void ParseData()
        {
            int offset = 0;
            while (offset + 29 <= _noteData.Count)
            {
                if (_noteData[offset] == 0x01 && _noteData[offset + 1] == 0x03 && _noteData[offset + 2] == 0x18)
                {
                    byte[] dataPacket = new byte[29];
                    Buffer.BlockCopy(_noteData.ToArray(), offset, dataPacket, 0, 29);

                    ParseReceivedData(dataPacket);

                    offset += 29;
                }
                else
                {
                    offset++;
                }
            }
        }

        private void ReadBuffer()
        {
            byte[] buffer = new byte[4096];
            var count = _stream.Read(buffer, 0, buffer.Count());
            if (_isNote)
            {
                if (count > 0)
                {
                    _noteData.AddRange(buffer.Take(count));
                }
            }
            else
            {
                _stopNote?.Set();
            }
            Thread.Sleep(10);
        }

        /// <summary>
        /// 解析接收到的数据包
        /// </summary>
        /// <param name="data">接收到的数据</param>
        private void ParseReceivedData(byte[] data)
        {
            if (data.Length < 5) return;

            byte address = data[0];
            byte opCode = data[1];
            byte dataLength = data[2];

            if (data.Length < 3 + dataLength + 2) return;

            byte[] registerData = new byte[dataLength];
            Array.Copy(data, 3, registerData, 0, dataLength);

            ParseRegisterValues(registerData);
        }

        /// <summary>
        /// 解析寄存器值并更新缓存
        /// </summary>
        /// <param name="data">寄存器数据</param>
        private void ParseRegisterValues(byte[] data)
        {
            for (int i = 0; i < data.Length; i += 2)
            {
                if (i + 1 >= data.Length) break;

                int registerAddress = i / 2;
                Int16 registerValue = (Int16)((data[i] << 8) | data[i + 1]);

                if (!_registerValues.ContainsKey(registerAddress))
                {
                    _registerValues[registerAddress] = new List<Int16>();
                }

                var registerHistory = _registerValues[registerAddress];
                registerHistory!.Add(registerValue);
            }
        }

        /// <summary>
        /// 断开TCP连接并停止所有任务
        /// </summary>
        public void Disconnect()
        {
            _isReading = false;
            _client?.Close();
        }
    }
}